#include <stdio.h>   /* */
#include <stdlib.h>  /* exit() */
#include <string.h>  /* memset(), memcpy() */
#include <sys/utsname.h>   /* uname() */
#include <sys/types.h>
#include <sys/socket.h>   /* socket(), bind(),
                             listen(), accept() */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>  /* fork(), write(), close() */

//TP1 Tomas Gutierrez, Nicolas Kappes, Dario Lamy.

/* Estructura de un alumno con sus atributos básicos */
typedef struct{
		int lu;
		char nombre[32];
		int nota;
	} Alumno;

/*Consulta y modificación del archivo alumnos.db, devuelve el resultado por referencia en el tercer parámetro.*/
void consulta(int, int, Alumno *); 

/*Crea un nuevo archivo alumnos.db con algunos registros para prueba, sobreescribe lo anteriores.*/
void inicializar(); 

int main(int argc,char **argv,char **envp) {

	/*Variables necesarias para la comunicación*/
	const int DEFAULT_PORT=8080;
	int z, r, port;
	int sck_inet, socketCliente;
	struct sockaddr_in adr_inet, cli_addr;
	int len_inet, cli_len;
	int buffer[2];
	char respuesta[256];

	/*Variables para la lógica del servidor*/
	int lu, nota;
	Alumno alumno;

	//inicializar(); //Crea el archivo alumnos.db con los registros iniciales.

	//Crear el socket.
	sck_inet = socket(AF_INET,SOCK_STREAM,0);

	//Crear una dirección.
	memset(&adr_inet,0,sizeof(adr_inet));

	if(argc>1){
		port=atoi(argv[1]);
	}else{
		//Si no se pasó ningun puerto por argumento asigna uno por defecto.
		port=DEFAULT_PORT;
	}

	adr_inet.sin_family = AF_INET;
	adr_inet.sin_port = htons(port);
	inet_aton("127.0.0.1",&adr_inet.sin_addr);

	len_inet = sizeof adr_inet;

	//Vincular el socket con la dirección.
	z = bind(sck_inet,
			(struct sockaddr *)&adr_inet,
			len_inet);

	if ( z == -1 ) {
		printf("Error haciendo bind()");
		exit(-1);
	}

	
	// Make it a listening socket:
	z = listen(sck_inet,10);
	if ( z == -1 ) {
		perror("Error en listen()");
		exit(-1);
	}

	printf("Servidor Mini Matero escuchando en el puerto %d.\n", port);

	while(1){
		printf("Esperando un cliente para atender...\n");
		
		socketCliente=accept(sck_inet, (struct sockaddr *)&cli_addr, &cli_len);
		
		bzero(buffer,2);
		read(socketCliente, buffer, sizeof(int)*2);
		
		printf("Consulta recibida: %d %d\n", buffer[0], buffer[1]);

		alumno.lu=buffer[0];
		alumno.nota=buffer[1];

		consulta(alumno.lu, alumno.nota, &alumno);

		if(alumno.lu==-1){
			//Alumno no encontrado.
			sprintf(respuesta,"Alumno %d no encontrado!\n", buffer[0]);
		}else if(alumno.nota==-1){
			//Encontró al alumno pero la nota no está asignada.
			sprintf(respuesta,"La nota de alumno %s (%d) no está asignada.\n", alumno.nombre, buffer[0]);
		}else{
			if(buffer[1]==-1){
				//Operación de consulta.
				sprintf(respuesta,"La nota del alumno %s (%d) es %d.\n", alumno.nombre, alumno.lu, alumno.nota);
			}else{
				//Operación de modificación.
				sprintf(respuesta,"La nota del alumno %s (%d) actualizada a %d.\n", alumno.nombre, alumno.lu, alumno.nota);	
			}
		}

		puts(respuesta);
		write(socketCliente, respuesta, sizeof(int)*256);		
	}

	close(sck_inet);
	printf("Cerrado.\n");
	
	return 0;
}

void consulta(int lu, int nota, Alumno *alumno){
	FILE *fp;
	char buffer[256];
	Alumno alumnoaux;
	int num_reg;

	num_reg=0; //Contador de registros leídos para calcular el offset.

	//printf("Abriendo alumnos.db...\n");
	fp = fopen ( "alumnos.db", "r+b" );

	alumno->lu=-1;
	alumno->nota=-1;
	
	while ((fread(&alumnoaux, sizeof(Alumno), 1, fp))!=0){
		if(alumnoaux.lu==lu){
			//Encontró el alumno.
			alumno->lu=alumnoaux.lu;
			strcpy(alumno->nombre,alumnoaux.nombre);
			if(nota==-1){
				//Devuelve la consulta.
				alumno->nota=alumnoaux.nota;
			}else{
				//Actualiza la nota.
				alumno->nota=nota;
				fseek (fp , sizeof(Alumno)*num_reg, SEEK_SET);
				fwrite(alumno, sizeof(Alumno),1, fp);
				fflush(fp);
			}
			break;
		}
		num_reg++; //Aumenta el número de registros leídos.
	}

	fclose ( fp );
}

void inicializar(){
	FILE *fp;
	Alumno alumno;

	printf("Inicializando alumnos.db...\n");
	fp = fopen ("alumnos.db", "a+b");

	alumno.lu=9999;
	alumno.nota=-1; //-1 significa que la nota no está asignada.
	strcpy(alumno.nombre, "Juan Perez");
	 
	fwrite(&alumno, sizeof(Alumno), 1, fp);
	
	alumno.lu=19160;
	alumno.nota=7;
	strcpy(alumno.nombre, "Tomas Gutierrez");
	 
	fwrite(&alumno, sizeof(Alumno), 1, fp);

	alumno.lu=19488;
	alumno.nota=8;
	strcpy(alumno.nombre, "Nicolas Kappes");

	fwrite(&alumno, sizeof(Alumno), 1, fp);

	alumno.lu=21059;
	alumno.nota=9;
	strcpy(alumno.nombre, "Dario Lamy");

	fwrite(&alumno, sizeof(Alumno), 1, fp);

	fclose(fp);

	printf("Archivo alumnos.db creado.\n");
}

